package org.gastomuito.server;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.gastomuito.client.ContabilidadeService;
import org.gastomuito.shared.RegistroContabilDTO;
import org.gastomuito.shared.RelatorioDespesaAnualDTO;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class ContabilidadeServiceImpl extends RemoteServiceServlet implements
        ContabilidadeService {

    private static final String CONTA_EMPRESA = "Empresa";

    private static final String CONTAS = "CONTAS";

    private static final String CONTA_RECEITA = "Receitas";

    private static final long serialVersionUID = -17849949251841091L;

    private static final String[] CONTAS_PADRAO = { "Aluguél", "Habitação",
            "Telefone celular", "Telefone", "Seguro do carro",
            "Seguro de vida", "Combustível", "Energia elétrica",
            "Alimentação/Super-mercado", "Férias/Viagem", "Água", "Roupas",
            "Empréstimos", "Internet", "Cabo", "Transporte", "Creche",
            "Médico", "Medicamento", "Ensino", "Estacionamento", "Babá",
            "Bichos estimação" };

    public RelatorioDespesaAnualDTO registrarReceita(
            RegistroContabilDTO registro) {
        ContaContabil contaReceita = getConta(CONTA_RECEITA);
        ContaContabil contaEmpresa = new ContaContabil(CONTA_EMPRESA);
        contaEmpresa.debitar(
                toAnual(registro.getQuantidade(), registro.getRepeticao()),
                contaReceita, registro.getQuando());
        return criarRelatorioDespesaAnual();
    }

    public RelatorioDespesaAnualDTO registrarDespesa(
            RegistroContabilDTO registro) {
        ContaContabil contaReceita = getConta(CONTA_RECEITA);
        ContaContabil contaDespesa = getConta(registro.getContaCredito());
        contaReceita.debitar(
                toAnual(registro.getQuantidade(), registro.getRepeticao()),
                contaDespesa, registro.getQuando());
        return criarRelatorioDespesaAnual();
    }

    @Override
    public String[] listaContasPadrao() {
        return CONTAS_PADRAO;
    }

    private RelatorioDespesaAnualDTO criarRelatorioDespesaAnual() {
        RelatorioDespesaAnualDTO relatorio = new RelatorioDespesaAnualDTO();
        Map<String, ContaContabil> contasPorNome = getContas();
        Collection<ContaContabil> contas = contasPorNome.values();
        int contaSize = 0;
        for (ContaContabil conta : contas) {
            if (CONTA_RECEITA.equals(conta.getNome())) {
                continue;
            }
            contaSize++;
        }
        String[] contasNome = new String[contaSize];
        double[] quantidades = new double[contaSize];
        double totalDespesas = 0.0;
        double totalReceitas = 0.0;
        double balanco = 0.0;
        int i = 0;
        for (ContaContabil conta : contas) {
            if (CONTA_RECEITA.equals(conta.getNome())) {
                totalReceitas = conta.totalPositivo();
                totalDespesas = conta.totalNegativo();
                balanco = conta.balanco();
            } else {
                contasNome[i] = conta.getNome();
                quantidades[i] = conta.balanco();
                i++;
            }
        }
        relatorio.setContas(contasNome);
        relatorio.setQuantidades(quantidades);
        relatorio.setTotalDespesas(totalDespesas);
        relatorio.setTotalReceitas(totalReceitas);
        relatorio.setBalanco(balanco);
        return relatorio;
    }

    private double toAnual(double valor, String repeticao) {
        if ("semana".equals(repeticao)) {
            valor = valor * 52;
        } else if ("mês".equals(repeticao)) {
            valor = valor * 12;
        }
        return valor;
    }

    private ContaContabil getConta(String contaNome) {
        Map<String, ContaContabil> contas = getContas();
        ContaContabil c = contas.get(contaNome);
        if (c == null) {
            c = new ContaContabil(contaNome);
            contas.put(contaNome, c);
            getSession().setAttribute(CONTAS, contas);
        }
        return c;
    }

    private Map<String, ContaContabil> getContas() {
        @SuppressWarnings("unchecked")
        Map<String, ContaContabil> contas =
                (Map<String, ContaContabil>) getSession().getAttribute(CONTAS);
        if (contas == null) {
            contas = new HashMap<String, ContaContabil>();
            getSession().setAttribute(CONTAS, contas);
        }
        return contas;
    }

    private HttpSession getSession() {
        return this.getThreadLocalRequest().getSession();
    }

}
